package com.ikingtech.framework.sdk.context.security;

import com.ikingtech.framework.sdk.utils.Tools;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tie yan
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Me {
    protected static final ThreadLocal<Identity> THREAD_LOCAL = new ThreadLocal<>();

    private static final String INVALID_DATA_SCOPE = "invalid_data_scope";

    public static void set(Identity value) {
        THREAD_LOCAL.remove();
        THREAD_LOCAL.set(value);
    }

    public static void clear() {
        THREAD_LOCAL.remove();
    }

    public static String id() {
        return info().getId();
    }

    public static String username() {
        return info().getUsername();
    }

    public static String name() {
        return info().getName();
    }

    public static String phone() {
        return info().getPhone();
    }

    public static List<String> categoryCodes() {
        return info().getCategoryCodes();
    }
    public static String lang() {
        return info().getLang();
    }

    public static String domainCode() {
        return info().getDomainCode();
    }

    public static String tenantCode() {
        return info().getTenantCode();
    }

    public static String appCode() {
        return info().getAppCode();
    }

    public static String menuId() {
        return info().getMenuId();
    }

    public static Object extension(String key) {
        return info().getExtensions().get(key);
    }

    public static Map<String, Object> extension() {
        return info().getExtensions();
    }

    public static boolean isAdmin() {
        return isAdmin(info());
    }

    public static Identity info() {
        return Optional.ofNullable(THREAD_LOCAL.get()).orElse(Identity.defaultUser());
    }

    public static List<String> dataScope() {
        return dataScope("");
    }

    public static List<String> dataScope(List<String> queryCodes) {
        return dataScope().stream().filter(queryCodes::contains).collect(Collectors.toList());
    }

    public static List<String> dataScope(String queryCode) {
        Identity me = info();
        List<String> dataScopeCodes = new ArrayList<>();
        if (isAdmin(me)) {
            return new ArrayList<>();
        }
        if (Tools.Coll.isBlank(me.getDataScopeCodes())) {
            // 非admin用户，并且没有权限码，返回无效权限
            return Collections.singletonList(INVALID_DATA_SCOPE);
        }
        if (null == queryCode || queryCode.isEmpty()) {
            // 查询权限码为空，则获取所有权限码
            dataScopeCodes.addAll(me.getDataScopeCodes());
        } else {
            dataScopeCodes.addAll(
                    me.getDataScopeCodes().stream()
                            // 获取查询权限码结尾的权限码
                            .filter(dataScopeCode ->
                                    null != dataScopeCode &&
                                            !dataScopeCode.isEmpty() &&
                                            dataScopeCode.regionMatches(true, dataScopeCode.length() - queryCode.length(), queryCode, 0, queryCode.length()))
                            // 获取以过滤后的权限码开头的权限码(子部门的全路径)
                            .map(dataScopeCode ->
                                    me.getDataScopeCodes().stream()
                                            .filter(scopeCode -> scopeCode.regionMatches(true, 0, dataScopeCode, 0, dataScopeCode.length()))
                                            .collect(Collectors.toList())
                            )
                            .flatMap(Collection::stream).toList()
            );
            if (dataScopeCodes.isEmpty()) {
                return Collections.singletonList(INVALID_DATA_SCOPE);
            }
        }
        // 将权限码(部门全路径)以@分割并去重后返回
        return dataScopeCodes.stream()
                .map(dataScopeCode -> {
                    String[] dataScopeArray = dataScopeCode.split("@");
                    return dataScopeArray[dataScopeArray.length - 1];
                })
                .distinct()
                .collect(Collectors.toList());
    }

    public static boolean invalidDataScope(List<String> dataScopeCodes) {
        return dataScopeCodes.contains(INVALID_DATA_SCOPE);
    }

    private static boolean isAdmin(Identity me) {
        return Tools.Coll.isNotBlank(me.getCategoryCodes()) && (me.getCategoryCodes().contains("PLATFORM_ADMINISTRATOR") || me.getCategoryCodes().contains("TENANT_ADMINISTRATOR"));
    }
}
